#include "remote_common.h"
#include "opencv_version.h"
#include "log_manager.h"

#include <opencv2/opencv.hpp>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/extensions/XTest.h>
#include <X11/Xutil.h>  // 辅助函数

#include <chrono>
#include <thread>
#include <unordered_set>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <atomic>
#include <stdexcept>
#include <iostream>

#define WINDOW_TITILE "Remote Desktop"

// 日志模块
static LogManager logger("client.log", 20 * 1024 * 1024);

// 1. 共享的 X11 Display 句柄（进程初始化时创建，全程不销毁，除非程序退出）
static Display* g_display = nullptr;
// 2. 保护 Display* 访问的互斥锁
static std::mutex g_display_mutex;

// 初始化 X11 连接（主进程/初始化线程调用）
bool X11_init() {
    g_display = XOpenDisplay(nullptr); // nullptr 表示使用默认 DISPLAY 环境变量（如 :0）
    if (g_display == nullptr) {
        std::cerr << "Failed to open X11 display!" << std::endl;
        return false;
    }
    return true;
}

// 释放 X11 连接（程序退出前调用，仅调用一次）
void X11_exit() {
    if (g_display != nullptr) {
        XCloseDisplay(g_display);
        g_display = nullptr;
    }
}

// 通过下面接口统一安全访问 g_display 实例

KeyCode X11_keysym_to_x11key(KeySym ks) { 
    std::lock_guard<std::mutex> lock(g_display_mutex);
    return XKeysymToKeycode(g_display, ks);
}

KeySym X11_x11key_to_keysym(KeyCode kc) { 
    std::lock_guard<std::mutex> lock(g_display_mutex);
    return XKeycodeToKeysym(g_display, kc, 0);
}

void X11_GetKeyMap(char keymap[])
{
    std::lock_guard<std::mutex> lock(g_display_mutex);
    XQueryKeymap(g_display, keymap);
}


// 辅助函数：判断是否为修饰键(Ctrl/Shift/Alt)
bool isModifierKey(KeyCode code) {

    KeySym sym = X11_x11key_to_keysym(code);
    return sym == XK_Control_L  || sym == XK_Control_R ||
           sym == XK_Shift_L    || sym == XK_Shift_R   ||
           sym == XK_Alt_L      || sym == XK_Alt_R;
}

// 辅助函数：发送按键事件（抽离重复代码）
void sendKeyEvent(int client_socket, KeyCode keycode, bool pressed) {
    KeyboardEvent event;
    event.keycode = keycode;
    event.pressed = pressed;
    
    PacketHeader header;
    header.type = KEYBOARD_EVENT;
    header.data_size = sizeof(KeyboardEvent);
    
    send_all(client_socket, &header, sizeof(header));
    send_all(client_socket, &event, sizeof(event));
}

// 客户端鼠标状态跟踪（用于检测拖拽）
struct ClientMouseState {
    bool left_button_down = false;  // 记录左键是否按下
    bool is_dragging = false;       // 当前是否处于拖拽状态
} client_mouse_state;

// 鼠标事件回调函数（更新拖拽检测）
void on_mouse(int event, int x, int y, int flags, void* userdata) {
    int* client_socket = static_cast<int*>(userdata);
    MouseEvent mouse_event;
    mouse_event.x = x;
    mouse_event.y = y;
    mouse_event.left_down = client_mouse_state.left_button_down;
    mouse_event.right_down = false;
    mouse_event.wheel_delta = 0;  // 默认为0
    mouse_event.dragging = false;

    //logger.log_debug("鼠标事件：event=%d, flags=%d, %d, %d", event, flags, x, y);

// #if (OPENCV_MAJOR_VERSION >= 4)
//     // 处理鼠标滚轮事件(旧版本没有EVENT_MOUSEWHEEL,opencv4才有)
//     if (event == cv::EVENT_MOUSEWHEEL) {
//         // OpenCV中，滚轮事件的flags高16位表示方向
//         printf("鼠标滚轮事件：%d\n", flags);
//         if (flags > 0) {
//             mouse_event.wheel_delta = 120;  // 向上滚动（Windows标准值）
//         } else {
//             mouse_event.wheel_delta = -120; // 向下滚动
//         }
//     }
// #endif // OPENCV_MAJOR_VERSION >= 4

    // 处理滚轮事件
    #if OPENCV_VERSION_AT_LEAST(4, 0)
        // OpenCV 4.x版本：使用EVENT_MOUSEWHEEL和EVENT_MOUSEHWHEEL
        if (
				(event == cv::EVENT_MOUSEWHEEL) ||
				(event == cv::EVENT_MOUSEHWHEEL) )
		{
            // 高16位表示垂直滚轮方向，正数向上，负数向下
            int delta = cv::getMouseWheelDelta(flags);
            // printf("鼠标滚轮事件: delta=%d, flags=%d\n", delta, flags);
            mouse_event.wheel_delta = delta;
			logger.log_debug("鼠标滚轮事件：event=%d, flags=%d, %d, %d, delta=%d", event, flags, x, y, delta);
        }
    #else
        // // OpenCV 3.x版本：通过flags的高16位判断
        // if (event == cv::EVENT_MOUSEWHEEL) {
        //     int delta = (flags >> 16) > 0 ? 120 : -120;
        //     mouse_event.wheel_delta = delta;
        // }
    #endif

    // 检测左键按下
	else if (event == cv::EVENT_LBUTTONDOWN) {
        client_mouse_state.left_button_down = true;
        client_mouse_state.is_dragging = false;  // 刚按下时还不算拖拽
        mouse_event.left_down = true;
    }
    // 检测左键释放
    else if (event == cv::EVENT_LBUTTONUP) {
        client_mouse_state.left_button_down = false;
        client_mouse_state.is_dragging = false;   // 释放时结束拖拽
        mouse_event.left_down = false;
    }
    // 检测鼠标移动
    else if (event == cv::EVENT_MOUSEMOVE) {
        // 如果左键已按下且正在移动，标记为拖拽状态
        if (client_mouse_state.left_button_down) {
            client_mouse_state.is_dragging = true;
            mouse_event.dragging = true;
        }
    }
    // 右键事件（保持不变）
    else if (event == cv::EVENT_RBUTTONDOWN) {
        mouse_event.right_down = true;
    }
    else if (event == cv::EVENT_RBUTTONUP) {
        mouse_event.right_down = false;
    }
    else {
        return;
    }

    // 发送鼠标事件
    PacketHeader header;
    header.type = MOUSE_EVENT;
    header.data_size = sizeof(MouseEvent);
    
    send_all(*client_socket, &header, sizeof(header));
    send_all(*client_socket, &mouse_event, sizeof(mouse_event));
}

#if 0
// 鼠标事件回调函数
void on_mouse(int event, int x, int y, int flags, void* userdata) {
    int* client_socket = static_cast<int*>(userdata);
    MouseEvent mouse_event;
    mouse_event.x = x;
    mouse_event.y = y;
    mouse_event.left_down = false;
    mouse_event.right_down = false;
    
    // 检测鼠标按键事件
    if (event == cv::EVENT_LBUTTONDOWN) {
        mouse_event.left_down = true;
    }
    else if (event == cv::EVENT_LBUTTONUP) {
        mouse_event.left_down = false;
    }
    else if (event == cv::EVENT_RBUTTONDOWN) {
        mouse_event.right_down = true;
    }
    else if (event == cv::EVENT_RBUTTONUP) {
        mouse_event.right_down = false;
    }
    // 鼠标移动也发送事件
    else if (event == cv::EVENT_MOUSEMOVE) {
        // 保持当前按键状态
    } else {
        //return; // 忽略其他事件
    }
    
    // 发送鼠标事件
    PacketHeader header;
    header.type = MOUSE_EVENT;
    header.data_size = sizeof(MouseEvent);
    
    send_all(*client_socket, &header, sizeof(header));
    send_all(*client_socket, &mouse_event, sizeof(mouse_event));
}
#endif //if 0

// 转换OpenCV键码到X11键码
uint16_t opencv_to_x11_key_simple(int key) {
    // 简化的键码映射表
    switch(key) {
        case 'a': return 38; case 'A': return 38;
        case 'b': return 56; case 'B': return 56;
        case 'c': return 54; case 'C': return 54;
        case 'd': return 40; case 'D': return 40;
        case 'e': return 26; case 'E': return 26;
        case 'f': return 41; case 'F': return 41;
        case 'g': return 42; case 'G': return 42;
        case 'h': return 43; case 'H': return 43;
        case 'i': return 31; case 'I': return 31;
        case 'j': return 44; case 'J': return 44;
        case 'k': return 45; case 'K': return 45;
        case 'l': return 46; case 'L': return 46;
        case 'm': return 58; case 'M': return 58;
        case 'n': return 57; case 'N': return 57;
        case 'o': return 32; case 'O': return 32;
        case 'p': return 33; case 'P': return 33;
        case 'q': return 24; case 'Q': return 24;
        case 'r': return 27; case 'R': return 27;
        case 's': return 39; case 'S': return 39;
        case 't': return 28; case 'T': return 28;
        case 'u': return 30; case 'U': return 30;
        case 'v': return 55; case 'V': return 55;
        case 'w': return 25; case 'W': return 25;
        case 'x': return 53; case 'X': return 53;
        case 'y': return 29; case 'Y': return 29;
        case 'z': return 52; case 'Z': return 52;
        case '0': return 19; case ')': return 19;
        case '1': return 10; case '!': return 10;
        case '2': return 11; case '@': return 11;
        case '3': return 12; case '#': return 12;
        case '4': return 13; case '$': return 13;
        case '5': return 14; case '%': return 14;
        case '6': return 15; case '^': return 15;
        case '7': return 16; case '&': return 16;
        case '8': return 17; case '*': return 17;
        case '9': return 18; case '(': return 18;
        case 27: return 9;   // ESC
        case 13: return 36;  // Enter
        case 32: return 65;  // Space
        case 8:  return 22;  // Backspace
        case 9:  return 23;  // Tab
        default: return 0;   // 未知键
    }
}

// rgb: 0=R, 1=G, 2=B
void screen_show_rgb(int rgb, int show_width, int show_height)
{
    // 用于存储屏幕数据的缓冲区
    std::vector<unsigned char> screen_buffer(show_width * show_height * PIXEL_BYTES);
    cv::Mat frame(show_height, show_width, CV_8UC3);

    // 根据 caller 传入的参数设置 RGB 值
    int RGB[3] = {0, 0, 0}; // R,G,B
    RGB[rgb%3] = 255;

    // 填充一张用于测试的纯色图片
    std::vector<unsigned char> screen_data(show_width * show_height * PIXEL_BYTES, 0);
    for (int i = 0; i < screen_data.size(); i += 3) {
        screen_data[i+0] = RGB[0]; // R
        screen_data[i+1] = RGB[1]; // G
        screen_data[i+2] = RGB[2]; // B
    }

    // 将RGB数据转换为OpenCV的BGR格式
    for (int y = 0; y < show_height; y++) {
        for (int x = 0; x < show_width; x++) {
            size_t index = (y * show_width + x) * PIXEL_BYTES;
            // OpenCV使用BGR格式
            frame.at<cv::Vec3b>(y, x)[0] = screen_data[index + 2]; // B
            frame.at<cv::Vec3b>(y, x)[1] = screen_data[index + 1]; // G
            frame.at<cv::Vec3b>(y, x)[2] = screen_data[index];     // R
        }
    }
    
    // 显示远程屏幕
    cv::imshow(WINDOW_TITILE, frame);
}

// 函数：判断指定 X11 KeyCode 的键是否被按住
// display：X11 显示连接，x11_keycode：目标键的 X11 KeyCode（如 0x26、0xa）
bool isKeyHeld(unsigned int x11_keycode) {
    // 1. X11 键盘状态缓冲区：32字节 = 256位，对应 256 个 KeyCode（0~255）
    char keymap[32] = {0};
    
    // 2. 读取当前键盘状态到缓冲区（全局生效，无需窗口聚焦）
    X11_GetKeyMap(keymap);
    
    // 3. 计算 x11_keycode 在缓冲区中的位置：
    // - 字节索引：x11_keycode / 8（每个字节存 8 个键的状态）
    // - 比特位索引：x11_keycode % 8（每个字节的第 n 位对应一个键）
    int byteIndex = x11_keycode / 8;
    int bitIndex = x11_keycode % 8;
    
    // 4. 判断该比特位是否为 1（1 = 按住，0 = 抬起）
    // 用 "1 << bitIndex" 生成掩码，与缓冲区字节做 "与运算"
    return ((keymap[byteIndex] & (1 << bitIndex)) != 0);
}

void key_click(int client_sockfd, KeyCode x11_key)
{
    sendKeyEvent(client_sockfd, x11_key, true);
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    sendKeyEvent(client_sockfd, x11_key, false);
}

void key_press(int client_sockfd, KeyCode x11_key)
{
    sendKeyEvent(client_sockfd, x11_key, true);
}

void key_release(int client_sockfd, KeyCode x11_key)
{
    sendKeyEvent(client_sockfd, x11_key, false);
}


// 检查并处理 "修饰键 + 鼠标点击" 的情况，如果修饰键不是持续按着，则发送释放键事件
// 处理那种非 "修饰键 + 普通键" 的情况，修饰键需要一个false事件来释放被控端对应的修饰键
void refresh_released_modifiers(int client_sockfd)
{
    KeyCode x11_key;

    // 如果下面这些修饰键没有被按着，则发送释放事件

    x11_key = X11_keysym_to_x11key(XK_Control_L);
    if (!isKeyHeld(x11_key))
        key_release(client_sockfd, x11_key);
    
    x11_key = X11_keysym_to_x11key(XK_Control_R);
    if (!isKeyHeld(x11_key))
        key_release(client_sockfd, x11_key);

    x11_key = X11_keysym_to_x11key(XK_Shift_L);
    if (!isKeyHeld(x11_key))
        key_release(client_sockfd, x11_key);

    x11_key = X11_keysym_to_x11key(XK_Shift_R);
    if (!isKeyHeld(x11_key))
        key_release(client_sockfd, x11_key);

    x11_key = X11_keysym_to_x11key(XK_Alt_L);
    if (!isKeyHeld(x11_key))
        key_release(client_sockfd, x11_key);

    x11_key = X11_keysym_to_x11key(XK_Alt_R);
    if (!isKeyHeld(x11_key))
        key_release(client_sockfd, x11_key);
}


enum cvKeyCode104 {
    CVKEY_HOLD_SHIFT = 0x10000,    // (1<<16) Shift键被按住时
    CVKEY_HOLD_CAPSLOCK = 0x20000, // (1<<17) 大写锁定键被点亮时, 0x20041
    CVKEY_HOLD_CTRL = 0x40000,     // (1<<18) Ctrl键被按住时，左右Ctrl相同
    CVKEY_HOLD_ALT = 0x80000,      // (1<<19) Alt键被按住时，左右Alt相同
    CVKEY_HOLD_MODIFIERS = CVKEY_HOLD_SHIFT | CVKEY_HOLD_CTRL | CVKEY_HOLD_ALT | CVKEY_HOLD_CAPSLOCK,
};



void keyboard_event_combo(int client_sockfd, int frame_delayms)
{
    refresh_released_modifiers(client_sockfd);

    int key1 = cv::waitKeyEx(10);
    if (key1 == -1) return ;

    int key2 = key1 & 0xffff;

    // 特殊键映射：OpenCV返回值 -> X11标准KeySym
    switch (key1) {
        case 27:          // OpenCV中ESC键的返回值
            key2 = XK_Escape;  // X11中ESC键的KeySym
            break;
        case 9:           // OpenCV中Tab键的返回值
            key2 = XK_Tab;     // X11中Tab键的KeySym
            break;
        case 13:          // OpenCV中Enter键的返回值
            key2 = XK_Return;  // X11中Enter键的KeySym
            break;
        // 可继续添加其他特殊键的映射
        default:
            // 非特殊键保持原有值
            break;
    }

    KeyCode x11_key = X11_keysym_to_x11key(key2);
    bool is_pressed = !(key1 & 0x80000000);  // 按下/释放判断

    // 测试结果: 按一下字母键时， is_pressed 为真
    // 长按键时，支持长按持续输出的键， is_pressed 会在循环中不断被赋值为真
    // if (is_pressed)
    // {
    //     logger.log_debug("key1=0x%x, key2=0x%x, x11_key=0x%x", key1, key2, x11_key);
    //     return ;
    // } else
    // {
    //     return ;
    // }

    if (x11_key == 0) {
        logger.log_warn("检测到不兼容CV按键: key1=0x%x, key2=0x%x, x11_key=0x%x", key1, key2, x11_key);
        logger.log_warn("请添加到特殊键映射, 以支持该按键键码识别");
        return ;
    }


    // 如果有按键被按下
    if (is_pressed)
    {
        // 首先确保按键按下触发的该代码

        // key1 是组合键的总值, 直接通过key1来判断是否存在组合键 (key1 & CVKEY_HOLD_MODIFIERS)

        // 情况1: 比如按下Ctrl + 鼠标点击，这种虽然有修饰键，但不是组合键

        // 情况2: 比如按下Shift + 鼠标点击，这种虽然有修饰键，但并不是组合键

        // 情况3: 比如按下Ctrl + Shift + 鼠标点击，这种虽然有修饰键，但并不是组合键

        // 情况4: 比如按下Ctrl + Shift + V键，这种就是组合键

        // 情况5: 比如按一下CapsLock键，key1=0xffe5, 再按一下CapsLock键，key1=0x2ffe5

        // CapsLock键只对字母有效，即大小写切换

        logger.log_debug("key1=0x%x, key2=0x%x, x11_key=0x%x", key1, key2, x11_key);


        // 首先处理单独按下 CapsLock键 的情况
        if ((key1 == XK_Caps_Lock) || (key1 == (XK_Caps_Lock | CVKEY_HOLD_CAPSLOCK))) {
            // 当执行到此处时，本地 CapsLock键已经被点亮，表示打开了大写锁定
            key_click(client_sockfd, x11_key);
            return ;
        }


        // 处理那种按住修饰键不放，然后又按其他普通键触发的情况
        if ((key1 & CVKEY_HOLD_MODIFIERS) != 0)
        {

            // 检测到任何一个被修饰键累加的按键值 key1 满足以下条件，则认为该按键被修饰键累加
            // 比如: Ctrl+Shift+C 复制选中内容到全局剪切板， Ctrl+Shift+V 粘贴全局剪切板
            if (( key1 & CVKEY_HOLD_CTRL) == CVKEY_HOLD_CTRL)
            {
                // 发送Ctrl键
                key_press(client_sockfd, X11_keysym_to_x11key(XK_Control_L));
            }
            if (( key1 & CVKEY_HOLD_SHIFT) == CVKEY_HOLD_SHIFT)
            {
                // 发送Shift键
                key_press(client_sockfd, X11_keysym_to_x11key(XK_Shift_L));
            }
            if (( key1 & CVKEY_HOLD_ALT) == CVKEY_HOLD_ALT)
            {
                // 发送Alt键
                key_press(client_sockfd, X11_keysym_to_x11key(XK_Alt_L));
            }

            // 紧接着单击一下普通键
            key_click(client_sockfd, x11_key);

            // 修饰键由 refresh_released_modifiers() 函数自动检测释放

        } else
        {
            // 要么是只按下了单个修饰键
            // 比如按住Shift，触发该代码，然后点鼠标，进行文件多选
            if (isModifierKey(x11_key))
            {
                // 发送按下的事件
                key_press(client_sockfd, x11_key);

            } else
            {
                // 要么是只按了普通键，发送普通按键，并紧接着发送释放操作
                key_click(client_sockfd, x11_key);
            }
        }


    } // if (is_pressed)

    return ;
}



bool keyboard_event_simple(int client_sockfd, int frame_delayms)
{
    // 2. 处理键盘事件
    int key = cv::waitKey(10);
    if (key == 27) { // ESC键退出
        logger.log_info("用户请求退出");
        return false;
    }
    else if (key != -1) { // 其他按键
        uint16_t x11_key = opencv_to_x11_key_simple(key);
        if (x11_key != 0) {
            // 发送按键按下事件
            KeyboardEvent press_event;
            press_event.keycode = x11_key;
            press_event.pressed = true;
            
            PacketHeader press_header;
            press_header.type = KEYBOARD_EVENT;
            press_header.data_size = sizeof(KeyboardEvent);
            
            send_all(client_sockfd, &press_header, sizeof(press_header));
            send_all(client_sockfd, &press_event, sizeof(press_event));
            
            // 短暂延迟后发送按键释放事件，模拟真实按键操作
            // usleep(50000); // 50ms延迟
            std::this_thread::sleep_for(std::chrono::milliseconds(frame_delayms));
            // std::this_thread::sleep_for(std::chrono::microseconds(1));

            
            KeyboardEvent release_event;
            release_event.keycode = x11_key;
            release_event.pressed = false;
            
            PacketHeader release_header;
            release_header.type = KEYBOARD_EVENT;
            release_header.data_size = sizeof(KeyboardEvent);
            
            send_all(client_sockfd, &release_header, sizeof(release_header));
            send_all(client_sockfd, &release_event, sizeof(release_event));
        }
    }
    return true;
}


// 创建客户端套接字，并连接到服务端特定的端口
// 通过 sockfd_client 参数返回套接字
bool connect_to_port(int &sockfd_client, const std::string &server_ip, int server_port)
{
    const char *server_ipstr = server_ip.c_str();
    sockfd_client = create_tcp_socket();
    if (sockfd_client < 0)
    {
        logger.log_error("创建网络套接字失败");
        return false;
    }

    sockaddr_in server_addr;
    std::memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    if (inet_pton(AF_INET, server_ipstr, &server_addr.sin_addr) <= 0) {
        logger.log_error("无效的IP地址,%s",strerror(errno));
        close(sockfd_client);
        return false;
    }
    
    if (connect(sockfd_client, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        logger.log_error("连接失败,%s",strerror(errno));
        close(sockfd_client);
        return false;
    }
    
    return true;
}


// 帧对象池：预分配cv::Mat实例，通过移动语义管理
class FramePool {
private:
    
    mutable std::mutex mutex_;          // 池锁
    int width_;                   // 帧宽度
    int height_;                  // 帧高度
    int type_;                    // 帧类型(CV_8UC3)
    size_t max_size_;             // 池最大容量
    std::queue<cv::Mat> pool_;          // 空闲帧池

    // 清空池内所有帧（内部辅助函数，需在已加锁状态下调用）
    void clear_pool() {
        while (!pool_.empty()) {
            pool_.pop();
        }
    }

public:
    // 构造函数：预分配指定数量的帧
    FramePool(int width = 1280, int height = 720, int type = CV_8UC3, size_t max_size = 500)
        : width_(width), height_(height), type_(type), max_size_(max_size) {
        // 预分配一半容量的帧（避免初始频繁分配）
        // size_t init_size = std::min(max_size / 2, size_t(3));
        // for (size_t i = 0; i < init_size; ++i) {
        //     pool_.emplace(height_, width_, type_);
        // }
    }

    // 从池中获取空闲帧（移动语义）
    cv::Mat acquire() {
        std::lock_guard<std::mutex> lock(mutex_);
        
        if (pool_.empty()) {
            // 池为空时创建新帧（不超过最大容量）
            if (pool_.size() >= max_size_) {
                throw std::runtime_error("FramePool is full");
            }
            return cv::Mat(height_, width_, type_);
        }
        
        // 从池取帧并移动所有权
        cv::Mat frame = std::move(pool_.front());
        pool_.pop();
        return frame;
    }

    // 将帧归还给池（移动语义）
    void release(cv::Mat&& frame) {
        // 验证帧格式是否匹配
        if (frame.cols != width_ || frame.rows != height_ || frame.type() != type_) {
            std::cerr << "Frame format mismatch, discarding" << std::endl;
            return;
        }

        std::lock_guard<std::mutex> lock(mutex_);
        
        // 池未满时才归还
        if (pool_.size() < max_size_) {
            // 清空帧数据但保留内存缓冲区
            frame.setTo(cv::Scalar(0, 0, 0));
            pool_.emplace(std::move(frame));
        }
        // 池满时自动释放帧（触发析构）
    }


    // 类方法：设置新的帧尺寸（线程安全）
    // 注意：调用后池内原有不匹配尺寸的帧会被清除
    void set_frame_size(int new_width, int new_height, int new_pool_size) {
        if (new_width <= 0 || new_height <= 0) {
            throw std::invalid_argument("无效的帧尺寸（宽高必须为正数）");
        }

        std::unique_lock<std::mutex> lock(mutex_);

        // 清除旧尺寸的帧
        clear_pool();

        // 更新尺寸
        width_ = new_width;
        height_ = new_height;
        max_size_ = new_pool_size;

        // 预分配少量新尺寸的帧
        const size_t init_size = std::min(max_size_ / 2, size_t(3));
        for (size_t i = 0; i < init_size; ++i) {
            pool_.emplace(height_, width_, type_);
        }
    }


    // 获取当前帧尺寸
    void get_frame_size(int& width, int& height) const {
        std::lock_guard<std::mutex> lock(mutex_);
        width = width_;
        height = height_;
    }



    // 获取当前空闲帧数量
    size_t idle_count() const {
        std::lock_guard<std::mutex> lock(mutex_);
        return pool_.size();
    }
};

// 基于移动语义的线程安全帧队列
class FrameQueue {
private:
    std::queue<cv::Mat> queue_;          // 存储帧的队列
    mutable std::mutex mutex_;           // 队列锁
    std::condition_variable cond_;       // 条件变量
    std::atomic<bool> is_running_;       // 运行标志
    size_t max_size_;              // 最大队列长度

public:
    FrameQueue(size_t max_size = 500) : is_running_(true), max_size_(max_size) {}

    ~FrameQueue() {
        stop();
    }

    // 移动方式入队
    bool push(cv::Mat&& frame) {
        std::unique_lock<std::mutex> lock(mutex_);
        
        // 等待队列有空间或停止信号
        cond_.wait(lock, [this]() {
            return !is_running_ || queue_.size() < max_size_;
        });

        if (!is_running_) return false;

        // 移动入队（无拷贝）
        queue_.emplace(std::move(frame));
        cond_.notify_one();
        return true;
    }

    // 移动方式出队
    bool pop(cv::Mat& frame) {
        std::unique_lock<std::mutex> lock(mutex_);
        
        // 等待队列有数据或停止信号
        cond_.wait(lock, [this]() {
            return !is_running_ || !queue_.empty();
        });

        if (!is_running_ && queue_.empty()) return false;

        // 移动出队（无拷贝）
        frame = std::move(queue_.front());
        queue_.pop();
        cond_.notify_one();
        return true;
    }

    void set_max_size(size_t max_size) {
        std::unique_lock<std::mutex> lock(mutex_);
        max_size_ = max_size;
    }

    void stop() {
        is_running_ = false;
        cond_.notify_all();
    }
};


#if 0
// 全局资源
FramePool frame_pool(1280, 720, CV_8UC3, 10);  // 1280x720的BGR帧，最大10个
FrameQueue frame_queue(5);                      // 队列最大缓存5帧

// 生产者线程
void producer_thread() {
    while (true) {
        try {
            // 1. 从池获取空闲帧（移动语义，无拷贝）
            cv::Mat frame = frame_pool.acquire();
            
            // 2. 填充帧数据（例如从屏幕捕获）
            capture_screen(frame);  // 假设此函数直接写入frame数据
            
            // 3. 移动到队列（无拷贝）
            if (!frame_queue.push(std::move(frame))) {
                // 队列停止时归还帧
                frame_pool.release(std::move(frame));
                break;
            }
        }
        catch (const std::exception& e) {
            std::cerr << "Producer error: " << e.what() << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    }
}

// 消费者线程
void consumer_thread() {
    cv::namedWindow("Remote Desktop", cv::WINDOW_NORMAL);
    cv::Mat frame;
    
    while (true) {
        // 1. 从队列取帧（移动语义，无拷贝）
        if (!frame_queue.pop(frame)) {
            break;
        }
        
        // 2. 显示帧
        cv::imshow("Remote Desktop", frame);
        
        // 3. 处理窗口事件
        if (cv::waitKey(1) == 27) {  // ESC退出
            frame_queue.stop();
            break;
        }
        
        // 4. 归还帧到池（移动语义，无拷贝）
        frame_pool.release(std::move(frame));
    }
    
    cv::destroyAllWindows();
}
#endif // if 0

// 全局资源
static FramePool frame_pool;  // 1280x720的BGR帧，最大10个
static FrameQueue frame_queue;    


void thread_recv_screen(const std::string &server_ip, int scaled_width, int scaled_height, int frame_delayms)
{
    // 连接屏幕服务端口
    int sockfd_screen = 0;
    logger.log_info("连接到服务器(屏幕端口): %s:%d ...", server_ip.c_str(), PORT_SCREEN);
    if (!connect_to_port(sockfd_screen, server_ip, PORT_SCREEN)) {
        logger.log_error("无法连接到服务器(屏幕端口)!");
        return ;
    }
    logger.log_info("连接到服务器(屏幕端口): %s:%d 成功", server_ip.c_str(), PORT_SCREEN);


    // 初始化最多500帧的缓冲区
    // frame_pool.set_frame_size(scaled_width, scaled_height, 500);
    // frame_queue.set_max_size(500);


    // 专门用来接收屏幕画面数据，并把数据处理好（比如解压等操作），存入某个队列中，窗口显示那边能直接获取并显示
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));

        // // 接收帧数据


        // // 1. 从池获取空闲帧（移动语义，无拷贝）
        // cv::Mat frame = frame_pool.acquire();

        // // 2. 填充帧数据（例如从屏幕捕获）

        // // 3. 移动到队列（无拷贝）
        // if (!frame_queue.push(std::move(frame))) {
        //     // 队列停止时归还帧
        //     frame_pool.release(std::move(frame));
        //     break;
        // }
    }

}


void thread_send_event(const std::string &server_ip, int sockfd_control, int frame_delayms)
{
    logger.log_info("正在连接到远程桌面服务端 %s", server_ip.c_str());
    logger.log_info("按ESC键退出");

    // 主控端窗口实际要缩放的分辨率
    // int scaled_width = SCREEN_WIDTH / 2;
    // int scaled_height = SCREEN_HEIGHT / 2;
    int scaled_width = 1920;
    int scaled_height = 1200;



    // 给被控端发送一些必要的参数，比如缩放分辨率等
    PacketHeader header;
    header.type = PacketType::CONFIG_DATA;
    header.data_size = sizeof(ConfigData);
    ConfigData config_data;
    config_data.scaled_screen_height = scaled_height;
    config_data.scaled_screen_width = scaled_width;
    send_all(sockfd_control, &header, sizeof(header));
    send_all(sockfd_control, &config_data, sizeof(config_data));

    // OpenCV 的 HighGUI 模块（负责窗口创建、鼠标回调等）不是线程安全的，
    // 所有窗口相关操作（创建窗口、设置回调、显示图像等）必须在 同一个线程 中执行
    // 若在多个线程中同时调用 namedWindow、setMouseCallback、imshow 等函数，可能导致窗口崩溃、回调失效或程序异常。
    {
        // 创建显示窗口
        cv::namedWindow(WINDOW_TITILE, cv::WINDOW_NORMAL);
        cv::resizeWindow(WINDOW_TITILE, scaled_width, scaled_height); // 缩小一半显示，适合大多数屏幕
        
        // 设置鼠标鼠标回调
        cv::setMouseCallback(WINDOW_TITILE, on_mouse, (void *)&sockfd_control);

        // 先显示一帧图像，且纯色图片
        screen_show_rgb(1, scaled_width, scaled_height);
    }


    // 等待屏幕服务就绪
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));




    // 连接屏幕服务端口
    int sockfd_screen = 0;
    logger.log_info("连接到服务器(屏幕端口): %s:%d ...", server_ip.c_str(), PORT_SCREEN);
    if (!connect_to_port(sockfd_screen, server_ip, PORT_SCREEN)) {
        logger.log_error("无法连接到服务器(屏幕端口)!");
        return ;
    }
    logger.log_info("连接到服务器(屏幕端口): %s:%d 成功", server_ip.c_str(), PORT_SCREEN);






    // 为了不影响性能，专门创建一个线程来接收屏幕数据，并把屏幕数据缓存起来，
    // 当前线程的相关窗口方法(cv::imshow)只是从缓存中获取数据并显示即可，无需复杂的处理，复杂的处理都交给屏幕数据接收线程
    // std::thread tscreen(thread_recv_screen, server_ip, scaled_width, scaled_height, frame_delayms);
    // tscreen.detach();

    
    while (true) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000/24));// fps=24



#if 1
        {
            // 用于存储屏幕数据的缓冲区
            static std::vector<unsigned char> screen_buffer(scaled_width * scaled_height * PIXEL_BYTES);
            static cv::Mat frame(scaled_height, scaled_width, CV_8UC3);


            // 1. 接收屏幕数据
            PacketHeader header;
            if (!recv_all(sockfd_screen, &header, sizeof(header))) {
                std::cerr << "接收数据失败，连接已断开" << std::endl;
                break;
            }
            
            // if (header.type == SCREEN_DATA && header.data_size == screen_buffer.size()) {
            // logger.log_debug("收到一帧图像");
            if (header.type == SCREEN_DATA) {
                if (recv_all(sockfd_screen, screen_buffer.data(), header.data_size)) {
                    // 将RGB数据转换为OpenCV的BGR格式
                    for (int y = 0; y < scaled_height; y++) {
                        for (int x = 0; x < scaled_width; x++) {
                            size_t index = (y * scaled_width + x) * PIXEL_BYTES;
                            // OpenCV使用BGR格式
                            frame.at<cv::Vec3b>(y, x)[0] = screen_buffer[index + 2]; // B
                            frame.at<cv::Vec3b>(y, x)[1] = screen_buffer[index + 1]; // G
                            frame.at<cv::Vec3b>(y, x)[2] = screen_buffer[index + 0]; // R
                        }
                    }

                    // logger.log_debug("显示一帧图像");
                    
                    // 显示远程屏幕
                    cv::imshow(WINDOW_TITILE, frame);
                    cv::waitKey(1);
                }
            }

        }

#endif //if 0




        // 键盘事件处理，用于调试
        // if (!keyboard_event_simple(sockfd_control, frame_delayms))
        // {
        //     break;
        // }

        // 键盘事件处理，支持组合键
        keyboard_event_combo(sockfd_control, frame_delayms);
    }
    cv::destroyAllWindows();
}




int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cerr << "用法: " << argv[0] << " <服务端IP地址> <FPS>" << std::endl;
        return 1;
    }
    
    const char* server_ip = argv[1];

    // 拿到 FPS
    int fps = std::stoi(argv[2]);
    int frame_delayms = 1000 / fps;


    // 初始化日志模块
    logger.setConsoleLogLevel(LogLevel::DEBUG);
    logger.setFileLogLevel(LogLevel::INFO);


    // 打印opencv版本信息
    print_opencv_version();


    // 初始化X11显示
    if (!X11_init())
    {
        return -1;
    }


    int sockfd_control = 0;

    // 连接控制服务端口
    logger.log_info("连接到服务器(控制端口): %s:%d ...", server_ip, PORT_CONTROL);
    if (!connect_to_port(sockfd_control, server_ip, PORT_CONTROL)) {
        logger.log_error("无法连接到服务器(控制端口)!");
        X11_exit();
        return -1;
    }
    logger.log_info("连接到服务器(控制端口): %s:%d 成功", server_ip, PORT_CONTROL);


    // 创建一个发送线程, 专门用来发送鼠标事件、键盘事件
    std::thread th_tx_event(thread_send_event, std::string(server_ip), sockfd_control, frame_delayms);
    th_tx_event.join();
    
    if (sockfd_control > 0) close(sockfd_control);
    X11_exit();
    return 0;
}

